; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s

declare void @llvm.assume(i1)
declare i8 @llvm.umin(i8, i8)
declare i8 @llvm.umax(i8, i8)
declare i8 @llvm.smin(i8, i8)
declare i8 @llvm.smax(i8, i8)

; If we don't know anything about the arguments, we can't do anything.

define i8 @test0(i8 %x, i8 %y) {
; CHECK-LABEL: @test0(
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
; CHECK-NEXT:    ret i8 [[R]]
;
  %r = call i8 @llvm.umin(i8 %x, i8 %y)
  ret i8 %r
}
define i8 @test1(i8 %x, i8 %y) {
; CHECK-LABEL: @test1(
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
; CHECK-NEXT:    ret i8 [[R]]
;
  %r = call i8 @llvm.umax(i8 %x, i8 %y)
  ret i8 %r
}
define i8 @test2(i8 %x, i8 %y) {
; CHECK-LABEL: @test2(
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
; CHECK-NEXT:    ret i8 [[R]]
;
  %r = call i8 @llvm.smin(i8 %x, i8 %y)
  ret i8 %r
}
define i8 @test3(i8 %x, i8 %y) {
; CHECK-LABEL: @test3(
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
; CHECK-NEXT:    ret i8 [[R]]
;
  %r = call i8 @llvm.smax(i8 %x, i8 %y)
  ret i8 %r
}

; However, if we do know the ranges of arguments, we sometimes can tell that either one is always picked.

define i8 @test4(i8 %x) {
; CHECK-LABEL: @test4(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 43
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp ule i8 %x, 43
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umin(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test5(i8 %x) {
; CHECK-LABEL: @test5(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;
  %lim = icmp ule i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umin(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test6(i8 %x) {
; CHECK-LABEL: @test6(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 42
;
  %lim = icmp uge i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umin(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test7(i8 %x) {
; CHECK-LABEL: @test7(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 41
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp uge i8 %x, 41
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umin(i8 %x, i8 42)
  ret i8 %r
}

define i8 @test8(i8 %x) {
; CHECK-LABEL: @test8(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 41
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp uge i8 %x, 41
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umax(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test9(i8 %x) {
; CHECK-LABEL: @test9(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;
  %lim = icmp uge i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umax(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test10(i8 %x) {
; CHECK-LABEL: @test10(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 42
;
  %lim = icmp ule i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umax(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test11(i8 %x) {
; CHECK-LABEL: @test11(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 43
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp ule i8 %x, 43
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.umax(i8 %x, i8 42)
  ret i8 %r
}

define i8 @test12(i8 %x) {
; CHECK-LABEL: @test12(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 43
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp sle i8 %x, 43
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smin(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test13(i8 %x) {
; CHECK-LABEL: @test13(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;
  %lim = icmp sle i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smin(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test14(i8 %x) {
; CHECK-LABEL: @test14(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 42
;
  %lim = icmp sge i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smin(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test15(i8 %x) {
; CHECK-LABEL: @test15(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp sge i8 %x, 41
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smin(i8 %x, i8 42)
  ret i8 %r
}

define i8 @test16(i8 %x) {
; CHECK-LABEL: @test16(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp sge i8 %x, 41
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smax(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test17(i8 %x) {
; CHECK-LABEL: @test17(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;
  %lim = icmp sge i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smax(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test18(i8 %x) {
; CHECK-LABEL: @test18(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 42
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 42
;
  %lim = icmp sle i8 %x, 42
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smax(i8 %x, i8 42)
  ret i8 %r
}
define i8 @test19(i8 %x) {
; CHECK-LABEL: @test19(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 43
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp sle i8 %x, 43
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.smax(i8 %x, i8 42)
  ret i8 %r
}
